Изчерпателно ръководство за оптимизиране на използването на паметта на Pandas, обхващащо типове данни, разделяне на части, категорични променливи и ефективни техники за работа с големи набори от данни.
Оптимизация на производителността на Pandas: Овладяване на намаляването на използването на паметта
Pandas е мощна Python библиотека за анализ на данни, предоставяща гъвкави структури от данни и инструменти за анализ на данни. Въпреки това, когато работите с големи набори от данни, използването на паметта може да се превърне в значителен проблем, влияещ върху производителността и дори причиняващ срив на вашите програми. Това изчерпателно ръководство изследва различни техники за оптимизиране на използването на паметта на Pandas, което ви позволява да обработвате по-големи набори от данни по-ефикасно и ефективно.
Разбиране на използването на паметта на Pandas
Преди да се потопите в техниките за оптимизация, е изключително важно да разберете как Pandas съхранява данните в паметта. Pandas основно използва NumPy масиви за съхраняване на данни в DataFrames и Series. Типът данни на всяка колона значително влияе върху използването на паметта. Например, колоната `int64` ще консумира два пъти повече памет от колоната `int32`.
Можете да проверите използването на паметта на DataFrame с помощта на метода .memory_usage():
import pandas as pd
data = {
'col1': [1, 2, 3, 4, 5],
'col2': ['A', 'B', 'C', 'D', 'E'],
'col3': [1.1, 2.2, 3.3, 4.4, 5.5]
}
df = pd.DataFrame(data)
memory_usage = df.memory_usage(deep=True)
print(memory_usage)
Аргументът deep=True е от съществено значение за точното изчисляване на използването на паметта на обектни (стрингови) колони.
Техники за намаляване на използването на паметта
1. Избор на правилните типове данни
Изборът на подходящия тип данни за всяка колона е най-фундаменталната стъпка за намаляване на използването на паметта. Pandas автоматично определя типовете данни, но често използва по-интензивни типове памет, отколкото е необходимо. Например, колона, съдържаща цели числа между 0 и 100, може да бъде присвоена тип `int64`, въпреки че `int8` или `uint8` биха били достатъчни.
Пример: Преобразуване на числени типове към по-малки
Можете да преобразувате числени типове към по-малки представяния с помощта на функцията pd.to_numeric() с параметъра downcast:
def reduce_mem_usage(df):
"""Iterate through all the columns of a dataframe and modify the data type
to reduce memory usage.
"""
start_mem = df.memory_usage().sum() / 1024**2
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))
for col in df.columns:
if df[col].dtype == 'object':
continue # Skip strings, handle them separately
col_type = df[col].dtype
if col_type in ['int64','int32','int16']:
c_min = df[col].min()
c_max = df[col].max()
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
else:
df[col] = df[col].astype(np.int64)
elif col_type in ['float64','float32']:
c_min = df[col].min()
c_max = df[col].max()
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
end_mem = df.memory_usage().sum() / 1024**2
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))
return df
Пример: Преобразуване на низове в категорични типове
Ако колона съдържа ограничен брой уникални стрингови стойности, преобразуването ѝ в категоричен тип може значително да намали използването на паметта. Категоричните типове съхраняват уникалните стойности само веднъж и представят всеки елемент в колоната като целочислен код, препращащ към уникалните стойности.
df['col2'] = df['col2'].astype('category')
Обмислете набор от данни за клиентски транзакции за глобална платформа за електронна търговия. Колоната „Държава“ може да съдържа само няколкостотин уникални имена на държави, докато наборът от данни съдържа милиони транзакции. Преобразуването на колоната „Държава“ в категоричен тип драстично ще намали консумацията на памет.
2. Разделяне на части и итерация
Когато работите с изключително големи набори от данни, които не могат да се поберат в паметта, можете да обработвате данните на части, като използвате параметъра chunksize в pd.read_csv() или pd.read_excel(). Това ви позволява да зареждате и обработвате данните на по-малки, управляеми парчета.
for chunk in pd.read_csv('large_dataset.csv', chunksize=100000):
# Process the chunk (e.g., perform calculations, filtering, aggregation)
print(f"Processing chunk with {len(chunk)} rows")
# Optionally, append results to a file or database.
Пример: Обработка на големи лог файлове
Представете си, че обработвате огромен лог файл от глобална мрежова инфраструктура. Лог файлът е твърде голям, за да се побере в паметта. Използвайки разделяне на части, можете да итерирате през лог файла, да анализирате всяка част за конкретни събития или модели и да обобщите резултатите, без да надвишавате ограниченията на паметта.
3. Избор само на необходимите колони
Често наборите от данни съдържат колони, които не са от значение за вашия анализ. Зареждането само на необходимите колони може значително да намали използването на паметта. Можете да зададете желаните колони, като използвате параметъра usecols в pd.read_csv().
df = pd.read_csv('large_dataset.csv', usecols=['col1', 'col2', 'col3'])
Пример: Анализ на данни за продажби
Ако анализирате данни за продажби, за да идентифицирате най-добре представящите се продукти, може да се нуждаете само от колоните „Идентификатор на продукта“, „Количество на продажбите“ и „Приходи от продажби“. Зареждането само на тези колони ще намали консумацията на памет в сравнение със зареждането на целия набор от данни, който може да включва демографски данни за клиентите, адреси за доставка и друга неподходяща информация.
4. Използване на разпръснати структури от данни
Ако вашият DataFrame съдържа много липсващи стойности (NaNs) или нули, можете да използвате разпръснати структури от данни, за да представите данните по-ефективно. Разпръснатите DataFrames съхраняват само нелипсващите или ненулевите стойности, което значително намалява използването на паметта при работа с разпръснати данни.
sparse_series = df['col1'].astype('Sparse[float]')
sparse_df = sparse_series.to_frame()
Пример: Анализ на оценки на клиенти
Обмислете набор от данни за оценки на клиенти за голям брой продукти. Повечето клиенти ще оценят само малка част от продуктите, което ще доведе до разпръсната матрица от оценки. Използването на разпръснат DataFrame за съхраняване на тези данни значително ще намали консумацията на памет в сравнение с плътен DataFrame.
5. Избягване на копиране на данни
Операциите Pandas понякога могат да създават копия на DataFrames, което води до увеличено използване на паметта. Модифицирането на DataFrame на място (когато е възможно) може да помогне да се избегне ненужно копиране.
Например, вместо:
df = df[df['col1'] > 10]
Помислете за използването на:
df.drop(df[df['col1'] <= 10].index, inplace=True)
Аргументът `inplace=True` променя DataFrame директно, без да създава копие.
6. Оптимизиране на съхранението на низове
Стринговите колони могат да консумират значителна памет, особено ако съдържат дълги низове или много уникални стойности. Преобразуването на низове в категорични типове, както беше споменато по-рано, е една ефективна техника. Друг подход е да използвате по-малки стрингови представяния, ако е възможно.
Пример: Намаляване на дължината на низа
Ако колона съдържа идентификатори, които се съхраняват като низове, но могат да бъдат представени като цели числа, преобразуването им в цели числа може да спести памет. Например, идентификатори на продукти, които в момента се съхраняват като низове като "PROD-1234", могат да бъдат съпоставени с цели идентификатори.
7. Използване на Dask за набори от данни, по-големи от паметта
За набори от данни, които са наистина твърде големи, за да се поберат в паметта, дори и с разделяне на части, помислете за използването на Dask. Dask е библиотека за паралелни изчисления, която се интегрира добре с Pandas и NumPy. Тя ви позволява да работите с набори от данни, по-големи от паметта, като ги разбиете на по-малки части и ги обработвате паралелно на множество ядра или дори множество машини.
import dask.dataframe as dd
ddf = dd.read_csv('large_dataset.csv')
# Perform operations on the Dask DataFrame (e.g., filtering, aggregation)
result = ddf[ddf['col1'] > 10].groupby('col2').mean().compute()
Методът compute() задейства действителното изчисление и връща Pandas DataFrame, съдържащ резултатите.
Най-добри практики и съображения
- Профилирайте кода си: Използвайте инструменти за профилиране, за да идентифицирате проблемите с паметта и да съсредоточите усилията си за оптимизация върху най-въздействащите области.
- Тествайте различни техники: Оптималната техника за намаляване на паметта зависи от специфичните характеристики на вашия набор от данни. Експериментирайте с различни подходи, за да намерите най-доброто решение за вашия случай на употреба.
- Наблюдавайте използването на паметта: Следете използването на паметта по време на обработката на данни, за да гарантирате, че вашите оптимизации са ефективни и да предотвратите грешки при липса на памет.
- Разберете данните си: Задълбоченото разбиране на вашите данни е от решаващо значение за избора на най-подходящите типове данни и техники за оптимизация.
- Обмислете компромисите: Някои техники за оптимизация на паметта могат да въведат леко забавяне на производителността. Преценете ползите от намаленото използване на паметта спрямо потенциалното въздействие върху производителността.
- Документирайте вашите оптимизации: Ясно документирайте техниките за оптимизация на паметта, които сте внедрили, за да гарантирате, че кодът ви е поддържан и разбираем от другите.
Заключение
Оптимизирането на използването на паметта на Pandas е от съществено значение за ефективната и резултатна работа с големи набори от данни. Като разберете как Pandas съхранява данните, избирате правилните типове данни, използвате разделяне на части и прилагате други техники за оптимизация, можете значително да намалите консумацията на памет и да подобрите производителността на вашите работни процеси за анализ на данни. Това ръководство предостави изчерпателен преглед на ключовите техники и най-добри практики за овладяване на намаляването на използването на паметта в Pandas. Не забравяйте да профилирате кода си, да тествате различни техники и да наблюдавате използването на паметта, за да постигнете най-добри резултати за вашия конкретен случай на употреба. Прилагайки тези принципи, можете да отключите пълния потенциал на Pandas и да се справите дори с най-взискателните предизвикателства за анализ на данни.
Като овладеят тези техники, учените и анализаторите на данни по целия свят могат да обработват по-големи набори от данни, да подобрят скоростта на обработка и да получат по-задълбочени познания от своите данни. Това допринася за по-ефективни изследвания, по-добре информирани бизнес решения и в крайна сметка за свят, основан на повече данни.